/******************************************************************************************************
Copyright (C) 2016 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/*globals  CommonSlots, MessageBox, NMRSpectrum, ProgressDialog, WebUtils, Application, Dir, Molecule, settings, File, TextStream, qsTr, mainWindow, nmr, FileDialog, serialization, dialog*/

/*jslint plusplus: true, indent: 4*/

function SyntheticPureShiftOptions() {
	'use strict';
}

//Static Attributes
SyntheticPureShiftOptions.automaticLineWidthKey = "Synthetic Pure Shift/Automatic LineWidth";
SyntheticPureShiftOptions.specificLineWidthKey = "Synthetic Pure Shift/Specific LineWidth";

//Static Methods
SyntheticPureShiftOptions.getAutomaticLineWidthKey = function () {
	'use strict';

	return settings.value(SyntheticPureShiftOptions.automaticLineWidthKey, true);
};

SyntheticPureShiftOptions.getSpecificLineWidthKey = function () {
	'use strict';

	return settings.value(SyntheticPureShiftOptions.specificLineWidthKey, 0.01);
};

function SyntheticPureShiftViewer() {
	'use strict';

	//Main vars
	var dialog, showDialog;

	//Initial GUI management
	dialog = {};
	dialog = Application.loadUiFile('ricares:SyntheticPureShift.ui');
	dialog.title = "Synthetic Pure Shift Settings";
	dialog.show();
	dialog.widgets.gbAutomaticLineWidth.checked = false;

	//Load Settings
	dialog.widgets.gbAutomaticLineWidth.checked = SyntheticPureShiftOptions.getAutomaticLineWidthKey();
	dialog.widgets.sbLineWidth.value = SyntheticPureShiftOptions.getSpecificLineWidthKey();

	showDialog = true;
	while (showDialog) {
		if (!dialog.exec()) {
			return;
		}

		showDialog = false;
	}

	//Save Settings
	settings.setValue(SyntheticPureShiftOptions.automaticLineWidthKey, dialog.widgets.gbAutomaticLineWidth.checked);
	settings.setValue(SyntheticPureShiftOptions.specificLineWidthKey, dialog.widgets.sbLineWidth.value);
}

function SyntheticPureShift() {
	'use strict';

	//Main vars and registries entries
	var currentDocument, sampleSpectrum, syntheticSpectrum, resultDocument, automaticWidth, specificWidth;

	SyntheticPureShift.getSampleSpectrum = function (aDocument) {

		var spectrum;

		if (aDocument.itemCount("NMR Spectrum") > 0) {
			spectrum = nmr.activeSpectrum();
			if (spectrum.nucleus() !== "1H") {
				MessageBox.critical("This script only runs with a 1H NMR spectrum type");
				spectrum = undefined;
			} else if (spectrum.peaks().count < 1) {
				MessageBox.critical("The current 1H NMR spectrum does not have a peaks analysis");
				spectrum = undefined;
			} else if (spectrum.proc.getParameter("PP.Method") !== "GSD") {
				MessageBox.critical("The current 1H NMR spectrum has not a GSD peaks analysis");
				spectrum = undefined;
			} else if (spectrum.multiplets().count === 0) {
				MessageBox.critical("The current 1H NMR spectrum does not have a multiplet analysis");
				spectrum = undefined;
			}
		} else {
			MessageBox.critical("There is not a 1H NMR spectrum within the current document");
		}

		return spectrum;
	};

	SyntheticPureShift.calculateMedian = function (aArray) {

		var median, half, totalElements;

		aArray.sort(function (a, b) {return a - b; });
		totalElements = aArray.length;
		half =  Math.floor(totalElements / 2);

		if (totalElements % 2) {
			median = aArray[half];
		} else {
			median = (aArray[half - 1] + aArray[half]) / 2.0;
		}

		return median;
	};

	SyntheticPureShift.getXMLPeaks = function (aSampleSpectrum, aLineWidth, aSpectrometerFrequency) {

		var i, j, xmlPeaks, currentMultiplet, currentPeak, peaks, totalPeaks, multiplets, height, shift, auxWidth, width, area;

		multiplets = aSampleSpectrum.multiplets();
		totalPeaks = multiplets.count;
		xmlPeaks = "";

		for (i = 0; i < totalPeaks; i++) {

			//Initialize vars and get current values
			currentMultiplet = multiplets.at(i);
			peaks = currentMultiplet.peaks;
			area = 0;
			auxWidth = [];

			//The area of the peak will correspond to the sum of all compound peaks within that multiplet
			for (j = 0; j < peaks.length; j++) {
				currentPeak = aSampleSpectrum.peaks().byId(peaks[j]);
				area += currentPeak.integral;
				if (aLineWidth === undefined) {
					auxWidth.push(currentPeak.width());
				}
			}

			//Either we get the median of the array or use the fixed value by converting units from Hz to ppm
			if (aLineWidth === undefined) {
				width = this.calculateMedian(auxWidth);
			} else {
				width = aLineWidth / aSpectrometerFrequency;
			}

			//Then, since we assump that each peak is a Lorentzian curve, its area will be done by pi*Width*Height)/2
			height = (2 * area) / (Math.PI * width);
			shift = multiplets.at(i).delta;
			xmlPeaks += "<peak>" +
						"<heigth>" + height + "</heigth>" +
						"<dim>" +
							"<shift>" + shift + "</shift>" +
							"<width>" + width + "</width>" +
						"</dim>" +
					"</peak>";
		}

		return xmlPeaks;
	};

	SyntheticPureShift.createSyntheticSpectrum = function (aSampleSpectrum, aDocument, aLineWidth) {

		var syntheticSpectrum, xml, currentSpectrumLimits, peaks, frequency;

		currentSpectrumLimits = aSampleSpectrum.getFullScaleLimits();
		frequency = aSampleSpectrum.getParam("Spectrometer Frequency");
		peaks = SyntheticPureShift.getXMLPeaks(aSampleSpectrum, aLineWidth, frequency);
		xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
				"<mnova-peaks version=\"" + Application.version.number + "\">" +
					"<spectrum>" +
						"<dim>" +
							"<from>" + currentSpectrumLimits.fromX + "</from>" +
							"<to>" + currentSpectrumLimits.toX + "</to>" +
							"<frequency>" + frequency + "</frequency>" +
							"<nucleus>" + aSampleSpectrum.nucleus() + "</nucleus>" +
							"<nPoints>" + aSampleSpectrum.getParam("Spectral Size") + "</nPoints>" +
							"<lineWidth>0.75</lineWidth>" +
						"</dim>" +
						"<solvent>" + aSampleSpectrum.getParam("Solvent") + "</solvent>" +
					"</spectrum>" +
					"<peakList>" + peaks +
				  "</peakList>" +
				"</mnova-peaks>";

		mainWindow.activeDocument = aDocument;
		syntheticSpectrum = nmr.syntheticPeaksSpectrum(xml);

		return syntheticSpectrum;
	};

	//----------------MAIN FUNCTION----------------

	//Get settings from registry
	automaticWidth = SyntheticPureShiftOptions.getAutomaticLineWidthKey();
	specificWidth = SyntheticPureShiftOptions.getSpecificLineWidthKey();
	if (automaticWidth) {
		specificWidth = undefined;
	}

	//Manage document, get sample spectrum and create synthetic spectrum
	currentDocument = mainWindow.activeDocument;
	sampleSpectrum = SyntheticPureShift.getSampleSpectrum(currentDocument);
	if (sampleSpectrum !== undefined) {
		resultDocument = mainWindow.newDocument();
		syntheticSpectrum = SyntheticPureShift.createSyntheticSpectrum(sampleSpectrum, resultDocument, specificWidth);
	}
}
